#ifndef __LOPPER_HPP__
#define __LOPPER_HPP__
#include <iostream>
#include <functional>
#include <memory>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include "buffer.hpp"

namespace sqy_log
{
    using Functor = std::function<void(Buffer&)>;
    enum class AsyncType
    {
        ASYNC_SAFE,//安全状态表示，缓冲区满了则阻塞
        ASYNC_UNSAFE//非安全状态表示无限扩容，用于性能测试
    };

    class AsyncLooper
    {
        public:
            AsyncLooper(const Functor& cb,AsyncType lopper_type = AsyncType::ASYNC_SAFE)
                :_stop(false)
                ,_thread(std::thread(&AsyncLooper::threadEntry,this))
                ,_callBack(cb)
                ,_lopper_type(lopper_type)
                {}
            using ptr = std::shared_ptr<AsyncLooper>;

            void stop()
            {
                _stop = true;//将退出标志设置为true
                _cond_con.notify_all();//唤醒所有的工作线程
                _thread.join();//等待工作线程的退出
            }

            void push(const char* data,size_t len)
            {
                //1.无限扩容-非安全 2.固定大小--生产缓冲区中数据满了就阻塞
                std::unique_lock<std::mutex>lock(_mutex);
                //条件变量空值，若缓冲区剩余空间大小大于数据长度，则可以添加数据
                if(_lopper_type == AsyncType::ASYNC_SAFE)
                    _cond_pro.wait(lock,[&](){return _pro_buf.writeAbleSize() >= len;});
                //能够走下来表示满足条件，可以向缓冲区添加数据
                _pro_buf.push(data,len);
                //唤醒消费者对缓冲区中数据进行处理
                _cond_con.notify_one();
            }
            ~AsyncLooper()
            {
                stop();
            }
        private:
            //线程入口函数--对消费缓冲区中的数据进行处理，处理完毕后，初始化缓冲区，交换缓冲区
            void threadEntry()
            {
                // 为互斥锁设置一个声明周期，当缓冲区交换完毕就解锁
                while(1)
                {
                    {
                        // 1.判断生产缓冲区有没有数据，有则交换，无则阻塞
                        std::unique_lock<std::mutex> lock(_mutex);
                        if(_stop && _pro_buf.empty()) break;
                        // 若当前是退出前被唤醒或者是有数据被唤醒，则返回真，继续向下运行，否则重新进入休眠
                        _cond_con.wait(lock, [&](){ return _stop || !_pro_buf.empty(); });
                        _con_buf.swap(_pro_buf);
                        // 2.唤醒生产者
                        if(_lopper_type == AsyncType::ASYNC_SAFE)
                            _cond_pro.notify_all();
                    }
                    // 3.被唤醒后，对消费者缓冲区进行数据处理
                    _callBack(_con_buf);
                    // 4.初始化消费者缓冲区
                    _con_buf.reset();
                }

            }
        private:
            Functor _callBack;//回调函数
        private:
            std::atomic<bool> _stop;//工作器停止标志
            Buffer _pro_buf;//生产者缓冲区
            Buffer _con_buf;//消费者缓冲区
            std::mutex _mutex;
            std::condition_variable _cond_pro;//消费者条件变量
            std::condition_variable _cond_con;//生产者条件变量
            std::thread _thread;//异步工作器的工作线程
            AsyncType _lopper_type;
    };
}
#endif